msg_tool\scripts\kirikiri\image/
tlg.rs

1//! Kirikiri TLG Image File (.tlg)
2use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::img::*;
6use anyhow::Result;
7use libtlg_rs::*;
8use std::io::{Read, Seek};
9
10#[derive(Debug)]
11/// Kirikiri TLG Script Builder
12pub struct TlgImageBuilder {}
13
14impl TlgImageBuilder {
15    /// Creates a new instance of `TlgImageBuilder`
16    pub const fn new() -> Self {
17        TlgImageBuilder {}
18    }
19}
20
21impl ScriptBuilder for TlgImageBuilder {
22    fn default_encoding(&self) -> Encoding {
23        Encoding::Cp932
24    }
25
26    fn build_script(
27        &self,
28        data: Vec<u8>,
29        _filename: &str,
30        _encoding: Encoding,
31        _archive_encoding: Encoding,
32        config: &ExtraConfig,
33        _archive: Option<&Box<dyn Script>>,
34    ) -> Result<Box<dyn Script>> {
35        Ok(Box::new(TlgImage::new(MemReader::new(data), config)?))
36    }
37
38    fn extensions(&self) -> &'static [&'static str] {
39        &["tlg", "tlg5", "tlg6"]
40    }
41
42    fn script_type(&self) -> &'static ScriptType {
43        &ScriptType::KirikiriTlg
44    }
45
46    fn is_image(&self) -> bool {
47        true
48    }
49
50    fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
51        if buf_len >= 11 {
52            if is_valid_tlg(buf) {
53                return Some(255);
54            }
55        }
56        None
57    }
58
59    fn can_create_image_file(&self) -> bool {
60        true
61    }
62
63    fn create_image_file<'a>(
64        &'a self,
65        mut data: ImageData,
66        writer: Box<dyn WriteSeek + 'a>,
67        _options: &ExtraConfig,
68    ) -> Result<()> {
69        if data.depth != 8 {
70            return Err(anyhow::anyhow!("Unsupported image depth: {}", data.depth));
71        }
72        let color_type = match data.color_type {
73            ImageColorType::Bgr => TlgColorType::Bgr24,
74            ImageColorType::Bgra => TlgColorType::Bgra32,
75            ImageColorType::Grayscale => TlgColorType::Grayscale8,
76            ImageColorType::Rgb => {
77                convert_rgb_to_bgr(&mut data)?;
78                TlgColorType::Bgr24
79            }
80            ImageColorType::Rgba => {
81                convert_rgba_to_bgra(&mut data)?;
82                TlgColorType::Bgra32
83            }
84        };
85        let tlg = Tlg {
86            width: data.width,
87            height: data.height,
88            color: color_type,
89            data: data.data,
90            tags: Default::default(),
91            version: 5, // Currently only version 5 is supported
92        };
93        save_tlg(&tlg, writer)?;
94        Ok(())
95    }
96}
97
98#[derive(Debug)]
99/// Kirikiri TLG Script
100pub struct TlgImage {
101    data: Tlg,
102}
103
104impl TlgImage {
105    /// Create a new TLG script
106    ///
107    /// * `data` - The reader containing the TLG script data
108    /// * `config` - Extra configuration options
109    pub fn new<T: Read + Seek>(data: T, _config: &ExtraConfig) -> Result<Self> {
110        let tlg = load_tlg(data)?;
111        Ok(TlgImage { data: tlg })
112    }
113}
114
115impl Script for TlgImage {
116    fn default_output_script_type(&self) -> OutputScriptType {
117        OutputScriptType::Json
118    }
119
120    fn default_format_type(&self) -> FormatOptions {
121        FormatOptions::None
122    }
123
124    fn is_image(&self) -> bool {
125        true
126    }
127
128    fn export_image(&self) -> Result<ImageData> {
129        Ok(ImageData {
130            width: self.data.width,
131            height: self.data.height,
132            color_type: match self.data.color {
133                TlgColorType::Bgr24 => ImageColorType::Bgr,
134                TlgColorType::Bgra32 => ImageColorType::Bgra,
135                TlgColorType::Grayscale8 => ImageColorType::Grayscale,
136            },
137            depth: 8,
138            data: self.data.data.clone(),
139        })
140    }
141
142    fn import_image<'a>(
143        &'a self,
144        mut data: ImageData,
145        file: Box<dyn WriteSeek + 'a>,
146    ) -> Result<()> {
147        if data.depth != 8 {
148            return Err(anyhow::anyhow!("Unsupported image depth: {}", data.depth));
149        }
150        let color_type = match data.color_type {
151            ImageColorType::Bgr => TlgColorType::Bgr24,
152            ImageColorType::Bgra => TlgColorType::Bgra32,
153            ImageColorType::Grayscale => TlgColorType::Grayscale8,
154            ImageColorType::Rgb => {
155                convert_rgb_to_bgr(&mut data)?;
156                TlgColorType::Bgr24
157            }
158            ImageColorType::Rgba => {
159                convert_rgba_to_bgra(&mut data)?;
160                TlgColorType::Bgra32
161            }
162        };
163        let tlg = Tlg {
164            width: data.width,
165            height: data.height,
166            color: color_type,
167            data: data.data,
168            tags: self.data.tags.clone(),
169            version: 5, // Currently only version 5 is supported
170        };
171        save_tlg(&tlg, file)?;
172        Ok(())
173    }
174}